package com.aplink.generic.widgets;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.location.Location;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.aplink.dellcommercial.R;
import com.aplink.generic.constant.ConfigParameter;
import com.aplink.generic.pojo.GenericObject;
import com.aplink.generic.pojo.xml.GeoMapConfig;
import com.aplink.generic.pojo.xml.GeoPointStatus;
import com.aplink.generic.util.AndroidUIParser;
import com.aplink.generic.util.LocationTracker;
import com.aplink.generic.xmlparser.GeoFormatParser;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MarkerOptions;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class MapFragment extends android.support.v4.app.Fragment {

    public static LocationTracker locationtracker;
    public static Activity mContext;

    private final ArrayList<GenericObject> genericTripList = new ArrayList<GenericObject>();

    private GeoMapConfig geoMapConfig;

    private ViewGroup layoutMapFragment;
    private String mapConfigFileName;

    private GoogleMap mMap;
    private int tripListSize;

    public static MapFragment newInstance( Activity parentActivity,
                                           String mapConfigFile, ArrayList<GenericObject> genericTripList ) {
        final MapFragment mapFragment = new MapFragment();
        final Bundle args = new Bundle();

        args.putString( "mapConfigFileName", mapConfigFile );
        args.putInt( "tripListSize", genericTripList.size() );

        // we need to divide genericTripList into putIntent with pre-defined key
        // as its order
        for ( int i = 0 ; i < genericTripList.size() ; i++ ) {
            args.putSerializable( ConfigParameter.GENERIC_OBJECT + i,
                    genericTripList.get( i ) );
        }

        mapFragment.setArguments( args );
        MapFragment.mContext = parentActivity;

        return mapFragment;
    }

    private Location latlngToLocation( LatLng dest ) {
        final Location loc = new Location( "" );
        loc.setLatitude( dest.latitude );
        loc.setLongitude( dest.longitude );
        return loc;
    }

    private void setProperZoomLevel( LatLng coordinates,
                                     ArrayList<LatLng> directionDesiredPoint, int radius, int nbPoi ) {
        // TODO Auto-generated method stub
        float currentZoomLevel = ConfigParameter.MAP_ZOOM_MAX;
        int currentFoundPoi = 0;
        LatLngBounds bounds = null;
        final List<LatLng> foundPoints = new ArrayList<LatLng>();
        final Location location = this.latlngToLocation( coordinates );
        boolean keepZoomingOut = true;
        boolean keepSearchingForWithinRadius = true;// this is true if we keep
        // looking
        // within a radius of 100km for ex:
        while ( keepZoomingOut ) {
            this.mMap.moveCamera( CameraUpdateFactory.newLatLngZoom( coordinates,
                    currentZoomLevel-- ) );
            bounds = this.mMap.getProjection().getVisibleRegion().latLngBounds;

            keepSearchingForWithinRadius = ( Math.round( location
                    .distanceTo( this.latlngToLocation( bounds.northeast ) ) / 1000 ) >
                    radius ) ? false
                    : true;

            // [2] find out if we have POI (Markers)
            for ( final LatLng k : directionDesiredPoint ) {
                if ( bounds.contains( k ) ) {
                    if ( ! foundPoints.contains( k ) ) {
                        currentFoundPoi++;
                        foundPoints.add( k );
                    }
                }
                // [3] we stop if we have nbPoi so far
                if ( keepSearchingForWithinRadius ) {
                    if ( currentFoundPoi > nbPoi ) {
                        keepZoomingOut = false;
                        break;

                    }// else keep looking

                } else if ( currentFoundPoi > 0 ) {// [4] We are beyond radius if
                    // we found one POI we are
                    // good
                    keepZoomingOut = false;
                    break;

                } else if ( currentZoomLevel < ConfigParameter.MAP_ZOOM_MIN ) {// [5]
                    // keep
                    // looking
                    // but
                    // within MIN_ZOOM
                    // limit (we don't
                    // want to go outer
                    // space do we ? :)
                    keepZoomingOut = false;
                    break;
                }
                // [6] if we didn't found nbPoi keep zooming out (within the
                // limit of radius)
            }
            keepZoomingOut = ( ( currentZoomLevel > 0 ) && keepZoomingOut ) ? true
                    : false;

        }
    }

    private void setUpMap() {

        final ArrayList<LatLng> directionDesiredPoint = new ArrayList<LatLng>();
        // we need to clear map firstly
        this.mMap.clear();

        for ( int i = 0 ; i < this.genericTripList.size() ; i++ ) {

            final GenericObject genericTripPojo = this.genericTripList.get( i );
            final String strLatitude = genericTripPojo
                    .getContentFromAttributeName( this.geoMapConfig.getLatitudeId() );
            final String strLongtitude = genericTripPojo
                    .getContentFromAttributeName( this.geoMapConfig.getLongitudeId() );
            if ( ( strLatitude != "" ) && ( strLongtitude != "" ) ) {

                final double latitude = Double.parseDouble( strLatitude );
                final double longtitude = Double.parseDouble( strLongtitude );
                final LatLng position = new LatLng( latitude, longtitude );

                directionDesiredPoint.add( position );

                // check status of this place in order to set suitably icons
                final String status = genericTripPojo
                        .getContentFromAttributeName( this.geoMapConfig.getStatusId() );
                final GeoPointStatus geoPointStatus = this.geoMapConfig
                        .getGeoPointStatusFromStatus( status );

                String title = "";
                if ( this.geoMapConfig.getIsDisplayAddress() == true ) {
                    title += genericTripPojo
                            .getContentFromAttributeName( this.geoMapConfig
                                    .getAddressId() );
                }

                final int drawableIcon = AndroidUIParser
                        .getDrawableIdByName( geoPointStatus.getmIcon() );
                this.mMap.addMarker( new MarkerOptions()
                        .position( position )
                        .title( title )
                        .snippet( geoPointStatus.getmSnippet() )
                        .icon( BitmapDescriptorFactory
                                .fromResource( drawableIcon ) ) );
            }
        }

        // get current position
        final Location location = MapFragment.locationtracker.getLocation();
        if ( location == null ) {
            this.showSettingsAlertInternet();
            return;
        }

        // set current location
        ConfigParameter.MAP_ZOOM_MAX = this.mMap.getMaxZoomLevel();
        ConfigParameter.MAP_ZOOM_MIN = this.mMap.getMinZoomLevel();
        this.mMap.setMyLocationEnabled( true );

        final double longtitude = location.getLongitude();
        final double latitude = location.getLatitude();
        final LatLng coordinates = new LatLng( latitude, longtitude );

        // set zoom level automatically
        // Delay the operation of finding the appropriate zoom level by giving
        // the Maps the time to added the Marker and initialize itself
        final TimerTask task = new TimerTask() {

            @Override
            public void run() {
                final Activity activity = MapFragment.mContext;
                activity.runOnUiThread( new Runnable() {

                    @Override
                    public void run() {
                        MapFragment.this.setProperZoomLevel( coordinates, directionDesiredPoint,
                                10, directionDesiredPoint.size() );
                    }
                } );

            }
        };

        final Timer timer = new Timer();
        timer.schedule( task, 1000 );// schedule Map display in 1 seconds

    }

    private void showSettingsAlertInternet() {
        final AlertDialog.Builder alertDialog = new AlertDialog.Builder(
                MapFragment.mContext );
        // Setting Dialog Title
        alertDialog.setTitle( "Network is settings" );
        // Setting Dialog Message
        alertDialog
                .setMessage( "Internet Connection is not available. Do you want to go to settings menu?" );
        // On pressing Settings button
        alertDialog.setPositiveButton( "Settings",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick( DialogInterface dialog, int which ) {
                        final Intent intent = new Intent(
                                WifiManager.ACTION_PICK_WIFI_NETWORK );
                        // intent.setClassName("com.android.phone",
                        // "com.android.phone.NetworkSetting");
                        MapFragment.mContext.startActivity( intent );
                    }
                } );

        // On pressing cancel button
        alertDialog.setNegativeButton( "Cancel",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick( DialogInterface dialog, int which ) {
                        dialog.cancel();
                    }
                } );

        // Showing Alert Message
        alertDialog.show();
    }

    @Override
    public void onCreate( Bundle savedInstanceState ) {
        super.onCreate( savedInstanceState );

        // return map Config file name
        this.mapConfigFileName = this.getArguments() != null ? this.getArguments()
                .getString( "mapConfigFileName" ) : "";

        this.tripListSize = this.getArguments() != null ? this.getArguments().getInt(
                "tripListSize" ) : - 1;

        // return array list of GenericTrip List
        for ( int i = 0 ; i < this.tripListSize ; i++ ) {
            final GenericObject genericObject = (GenericObject) this.getArguments()
                    .getSerializable( ConfigParameter.GENERIC_OBJECT + i );
            this.genericTripList.add( genericObject );
        }

        // get geoMapConfig
        this.geoMapConfig = new GeoMapConfig();
        this.geoMapConfig = GeoFormatParser.parserGeoMapConfig( MapFragment.mContext,
                this.mapConfigFileName, ConfigParameter.MAP_GEOMAPCONFIG );

    }

    @Override
    public View onCreateView( LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState ) {

        // we should check the size of genericTripList
        if ( this.genericTripList.size() == 0 ) {
            return null;
        }
        // we should get the viewGroup
        this.layoutMapFragment = (ViewGroup) inflater.inflate(
                R.layout.aplink__generic_map_plot, null );

        // we should check the location tracker
        MapFragment.locationtracker = new LocationTracker( MapFragment.mContext );
        // canGetLocation ?
        if ( MapFragment.locationtracker.canGetLocation() == true ) {

            // use to draw map at here
            // if there has list of destination, draw and link them on the map
            // and show your current location
            if ( this.mMap == null ) {
                // Try to obtain the map from the SupportMapFragment.
                this.mMap = ( (SupportMapFragment) this.getFragmentManager()
                        .findFragmentById( R.id.map4 ) ).getMap();
                // Check if we were successful in obtaining the map.
                if ( this.mMap != null ) {
                    this.setUpMap();
                }
            }
        } else {
            // //GPS or Network is not enabled, ask user to enable GPS/network
            // in settings
            this.showSettingsAlert();
        }

        // return view
        return this.layoutMapFragment;
    }

    @Override
    public void onPause() {
        super.onPause();
        MapFragment.locationtracker.stopUsingTracker();
    }

    @Override
    public void onResume() {

        super.onResume();
        this.setUpMap();
        MapFragment.locationtracker.continuetoGetLocation();
    }

    public void showSettingsAlert() {
        final AlertDialog.Builder alertDialog = new AlertDialog.Builder(
                MapFragment.mContext );
        // Setting Dialog Title
        alertDialog.setTitle( "GPS is settings" );
        // Setting Dialog Message
        alertDialog
                .setMessage( "GPS is not enabled. Do you want to go to settings menu?" );
        // On pressing Settings button
        alertDialog.setPositiveButton( "Settings",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick( DialogInterface dialog, int which ) {
                        final Intent intent = new Intent(
                                Settings.ACTION_LOCATION_SOURCE_SETTINGS );
                        MapFragment.mContext.startActivity( intent );
                    }
                } );

        // On pressing cancel button
        alertDialog.setNegativeButton( "Cancel",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick( DialogInterface dialog, int which ) {
                        dialog.cancel();
                    }
                } );

        // Showing Alert Message
        alertDialog.show();
    }

}
